package com.douxg.learning.springboot.base.youxi.serrvice;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.douxg.learning.springboot.base.youxi.shuipaixu.Cup;
import com.douxg.learning.springboot.base.youxi.shuipaixu.ShuiPaiXu;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @Description
 * @Auther douxg
 * @Date 2022/9/17 23:21
 */
@Data
@Slf4j
public class ShuiPaiXuService extends Thread {
    /**
     * 日志最大步数
     */
    private Integer logMaxStep = 0;
    private ShuiPaiXu shuiPaiXu;
    private long start;

    @Override
    public void run() {
        if (shuiPaiXu != null) {
            run(shuiPaiXu);
        }
    }

    public void run(ShuiPaiXu shuiPaiXu) {
        start = System.currentTimeMillis();
        if (shuiPaiXu.getMaxStep() == null) {
            shuiPaiXu.setMaxStep(Integer.MAX_VALUE);
        }
        if (shuiPaiXu.getWaitTime() == null) {
            shuiPaiXu.setWaitTime(3000L);
        }
        if (shuiPaiXu.getCupCapacity() == null) {
            shuiPaiXu.setCupCapacity(4);
        }
        if (shuiPaiXu.getResult() == null) {
            shuiPaiXu.setResult(new ArrayList<>());
        }
        List<Cup> cups = shuiPaiXu.getCups();
        Integer cupCapacity = shuiPaiXu.getCupCapacity();
        for (int i = cups.size() - 1; i >= 0; i--) {
            Cup cup = cups.get(i);
            Integer capacity = cup.getCapacity();
            if (capacity == null) {
                capacity = cupCapacity;
                cup.setCapacity(capacity);
            }
            List<String> things = cup.getThings();
            if (things == null) {
                cup.setThings(new ArrayList<>(capacity));
            } else if (things.size() > capacity) {
                throw new RuntimeException("杯子所装东西超过了容量");
            } else if (things.size() == 0) {
                cups.remove(i);
            }
        }
        List<String> steps = shuiPaiXu.getSteps();
        if (steps != null && steps.size() > 0) {
            for (String step : steps) {
                String[] split = step.split(">");
                int i = Integer.parseInt(split[0]);
                int j = Integer.parseInt(split[1]);
                if (i == j) {
                    continue;
                }
                Cup cup1 = cups.get(i);
                Cup cup2 = cups.get(j);
                dos(cup1, cup2, i, j);
            }
        }
        try {
            dos(cups, steps);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public void run(String json) {
        ShuiPaiXu shuiPaiXu = JSONObject.parseObject(json, ShuiPaiXu.class);
        run(shuiPaiXu);
    }

    public boolean dos(List<Cup> cups, List<String> log) {
        if (shuiPaiXu.getResult().size() > 0 && System.currentTimeMillis() - start > shuiPaiXu.getWaitTime()) {
            throw new RuntimeException("时间到了");
        }
        if (log != null) {
            if (log.size() >= shuiPaiXu.getMaxStep()) {
                return false;
            }
            if (log.size() > logMaxStep) {
                logMaxStep = log.size();
                System.out.println(logMaxStep);
            }
        }
        //判断是否全是空杯或者纯色满杯
        boolean allEmptyCup = true;
        for (int i = cups.size() - 1; i >= -0; i--) {
            Cup cup = cups.get(i);
            allEmptyCup = allEmptyCup && (cup.getThings().size() == 0 || isFinishCup(cup));
            if (!allEmptyCup) {
                break;
            }
        }
        //全是空杯则完成
        if (allEmptyCup) {
            if (log != null) {
                if (log.size() < shuiPaiXu.getMaxStep()) {
                    shuiPaiXu.setMaxStep(log.size());
                }
                String resultStep = "总步数：" + log.size() + "~~~~~~~开始~~~~~~~" + StrUtil.join(",", log) + "~~~~~~~结束~~~~~~~~~";
                shuiPaiXu.getResult().add(0, resultStep);
                System.out.println(resultStep);
            }
            return true;
        }
        for (int i = 0; i < cups.size(); i++) {
            Cup cup = cups.get(i);
            if (!checkTarget(cups.get(i))) {
                continue;
            }
            for (int j = 0; j < cups.size(); j++) {
                Cup cup2 = cups.get(j);
                if (i == j || !checkSource(cup2) || !checkSourceTarget(cup2, cup)) {
                    continue;
                }
                List<Cup> clone = clone(cups);
                List<String> subLog = log;
                if (subLog == null) {
                    subLog = new LinkedList<>();
                }
                if (!dos(clone.get(j), clone.get(i), j, i)) {
                    continue;
                }
                subLog.add((j + 1) + ">" + (i + 1));
                dos(clone, subLog);
                subLog.remove(subLog.size() - 1);
            }
        }
        return false;
    }

    public boolean checkSource(Cup cup) {
        List<String> things = cup.getThings();
        return things.size() > 0;
    }

    public boolean checkTarget(Cup cup) {
        List<String> things = cup.getThings();
        return things.size() < cup.getCapacity();
    }

    public boolean checkSourceTarget(Cup source, Cup target) {
        List<String> things1 = source.getThings();
        List<String> things2 = target.getThings();
        if (things2.size() == 0) {
            if (isSameColor(source)) {
                return false;
            }
        } else if (!things1.get(0).equals(things2.get(0))) {
            return false;
        }
        return true;
    }

    public boolean dos(Cup cup1, Cup cup2, int i, int j) {
        List<String> things1 = cup1.getThings();
        List<String> things2 = cup2.getThings();
        int surplusCapacity = cup2.getCapacity() - things2.size();
        if (things2.size() == 0) {
            List<String> things = getThings(things1);
            if (things.size() <= surplusCapacity) {
                things2.addAll(0, things);
                return true;
            }
        } else {
            List<String> things = getThings(things1);
            if (things.size() <= surplusCapacity) {
                things2.addAll(0, things);
                return true;
            }
        }
        return false;
    }

    public List<String> getThings(List<String> things) {
        List<String> result = null;
        if (things.size() == 0) {
            return result;
        }
        result = new ArrayList<>();
        String remove1 = things.remove(0);
        result.add(remove1);
        if (things.size() == 0) {
            return result;
        }
        int size = things.size();
        for (int i = 0; i < size; i++) {
            String remove2 = things.remove(0);
            if (remove2.equals(remove1)) {
                result.add(remove2);
            } else {
                things.add(0, remove2);
                break;
            }
        }
        return result;
    }

    /**
     * 判断杯子是否满容量同色杯
     *
     * @param cup
     * @return
     */
    public boolean isFinishCup(Cup cup) {
        return cup.getThings().size() == cup.getCapacity() && isSameColor(cup);
    }

    /**
     * 判断杯子中的东西是否同色
     *
     * @param cup
     * @return
     */
    public boolean isSameColor(Cup cup) {
        if (cup.getIsSameColor() != null && cup.getIsSameColor()) {
            return true;
        }
        List<String> things = cup.getThings();
        if (things.size() == 0) {
            return false;
        }
        boolean result = isSameColor(things);
        cup.setIsSameColor(true);
        return result;
    }

    /**
     * 判断杯子中的东西是否同色
     *
     * @param things
     * @return
     */
    public boolean isSameColor(List<String> things) {
        String remove = things.get(0);
        boolean result = true;
        for (int i = 1; i < things.size(); i++) {
            result = result && remove.equals(things.get(i));
            if (!result) {
                return false;
            }
        }
        return result;
    }


    /**
     * 克隆
     *
     * @return
     */
    public List<Cup> clone(List<Cup> cups) {
        List<Cup> cupList = new ArrayList<>();
        for (Cup cup : cups) {
            cupList.add(cup.myClone());
        }
        return cupList;
    }
}
